﻿#region Directives

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate; 

#endregion

namespace My.Data.Factories
{
    public class ISessionManager
    {
        #region Static Content

        private static ISessionManager _ISessionManager = null;

        /// <summary>
        /// Set method is exposed so that the IISessionManager can be swapped out for Unit Testing.
        /// NOTE: Cannot set Instance after it has been initialized, and calling Get will automatically intialize the Instance.
        /// </summary>
        public static ISessionManager Instance
        {
            get
            {
                if (_ISessionManager == null)
                    _ISessionManager = new ISessionManager();
                return _ISessionManager;
            }
            set
            {
                if (_ISessionManager != null)
                    throw new Exception("Cannot set Instance after it has been initialized.");
                _ISessionManager = value;
            }
        }

        #endregion

        #region Fields

        private ISessionFactory _SessionFactory = null;
        private const string SESSIONKEY = "ISession-ContextKey";

        #endregion

        #region Constructors

        /// <summary>
        /// This will load the NHibernate settings from the App.config.
        /// Note: This can/should be expanded to support multiple databases.
        /// </summary>
        private ISessionManager()
        {
            _SessionFactory = new NHibernate.Cfg.Configuration().Configure().BuildSessionFactory();
        }

        /// <summary>
        /// Releases unmanaged resources and performs other cleanup operations before the
        /// <see cref="ISessionManager"/> is reclaimed by garbage collection.
        /// </summary>
        ~ISessionManager()
        {
            Dispose(true);
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets the ISession.
        /// </summary>
        /// <value>The ISession.</value>
        public ISession ISession
        {
            get
            {
                if (ContextSession == null)
                    ContextSession = _SessionFactory.OpenSession();
                return ContextSession;
            }
        }

        /// <summary>
        /// Gets or sets the context session.
        /// </summary>
        /// <value>The context session.</value>
        private ISession ContextSession
        {
            get
            {
                return (ISession)System.Runtime.Remoting.Messaging.CallContext.GetData(SESSIONKEY);
            }
            set
            {
                System.Runtime.Remoting.Messaging.CallContext.SetData(SESSIONKEY, value);
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Creates the I session.
        /// </summary>
        /// <returns></returns>
        public ISession CreateISession()
        {
            ISession iSession;
            lock (_SessionFactory)
            {
                iSession = _SessionFactory.OpenSession();
            }
            return iSession;
        }

        #endregion
        
        #region IDisposable

        private bool _isDisposed = false;

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        public void Dispose()
        {
            Dispose(false);
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="finalizing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        private void Dispose(bool finalizing)
        {
            if (!_isDisposed)
            {
                // Close SessionFactory
                _SessionFactory.Close();
                _SessionFactory.Dispose();

                // Flag as disposed.
                _isDisposed = true;
                if (!finalizing)
                    GC.SuppressFinalize(this);
            }
        }

        #endregion
    }
}
